package com.issac.config;

import com.issac.filter.CaptchaFilter;
import com.issac.filter.JWTAuthenticationFilter;
import com.issac.filter.JwtAuthenticationEntryPoint;
import com.issac.handler.LoginFailureHandler;
import com.issac.handler.LoginSuccessHandler;
import com.issac.service.serviceImpl.UserServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;

/**
 * @ClassName SecurityConfig
 * @Author zy
 * @Date 2021/10/27 20:07
 * @Description SecurityConfig
 * @Version 1.0
 */
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private UserServiceImpl userDetailsService;

    @Autowired
    private CaptchaFilter captchaFilter;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 表单提交
        http.formLogin()
                // 登录成功后跳转页面，POST请求
                .successHandler(loginSuccessHandler())
                .failureHandler(loginFailureHandler())
                .usernameParameter("accountId")
                .passwordParameter("password")
                .and().exceptionHandling()
                .authenticationEntryPoint(jwtAuthenticationEntryPoint())
                .and().addFilter(jwtAuthenticationFilter());

        // 记住我
        http.rememberMe()
                // 自定义参数
//                .rememberMeParameter()
                // 自定义失效时间，默认2周
//                .tokenValiditySeconds()
                // 自定义功能实现逻辑
//                .rememberMeServices()

                // 自定义登录逻辑
                .userDetailsService(userDetailsService)
                // 存储位置
                .tokenRepository(persistentTokenRepository())

                .and().authorizeRequests()
                // login.html不需要被认证
                .antMatchers("/login", "/register", "/captcha").permitAll()
                // 所有请求都必须被认证，必须登录后被访问
                .anyRequest().authenticated()
                .and()
                // 禁用session
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                // 验证码过滤器
                .and().addFilterBefore(captchaFilter, UsernamePasswordAuthenticationFilter.class);

                // 登录
                http.userDetailsService(userDetailsService);

        // 关闭csrf防护
        http.csrf().disable()
                // 设置跨域，若不设置，即使配置了filter,也不会生效
                .cors();

    }

    @Autowired
    DataSource dataSource;

    // 存储token以实现记住我
    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
        tokenRepository.setDataSource(dataSource);
        //系统在启动的时候生成“记住我”的数据表（只能使用一次）
//        tokenRepository.setCreateTableOnStartup(true);
        return tokenRepository;
    }

    @Bean
    public LoginFailureHandler loginFailureHandler() {
        return new LoginFailureHandler();
    }

    // 加密
    @Bean
    public PasswordEncoder getPw() {
        return new BCryptPasswordEncoder();
    }

    // 登陆成功处理
    @Bean
    public LoginSuccessHandler loginSuccessHandler() {
        return new LoginSuccessHandler();
    }

    // 认证token
    @Bean
    public JWTAuthenticationFilter jwtAuthenticationFilter() throws Exception {
        return new JWTAuthenticationFilter(authenticationManager());
    }

    // 认证token失败
    public JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint() {
        return new JwtAuthenticationEntryPoint();
    }
}
